#include	"LoginService.h"
#include	"CenterConnector.h"

#include	<protocols/Common.pb.h>
#include	<protocols/Login.pb.h>
#include	<Utils.h>

using namespace Proto::Login;

extern void VerifySimple(Sender *, const std::string &, uint32_t, const std::string &, uint32_t);
extern void VerifySina(Sender *, const std::string &, uint32_t, const std::string &, uint32_t);

void LoginService::OnClose(Sender * sender, ENet::Close reason) {
	IBaseService::OnClose(sender, reason);

	for (auto & kv : _processing) {
		if (kv.second == sender->Id()) {
			_processing.erase(kv.first);
			break;
		}
	}
}

void LoginService::OnReceive(Sender * sender, Protocol * msg) {
	int pf = msg->pf;
	uint32_t serial = msg->serial;

	if (pf == Proto::REQ_VERIFY) {
		ReqVerify * req = Cast<ReqVerify>(msg);
		if (!req) return;

		int version = (int)req->version();
		if (version != _ver) {
			LOG_ERR("[login]Verify failed. Version(%d => %d)", _ver, version);
			FailedVerify(sender, Proto::S_EVersion, serial);
			return;
		}

		int sid = (int)req->sid();
		if (_valid_servers.find(sid) == _valid_servers.end()) {
			LOG_ERR("[login]Verify failed. Invalid sid : %d", sid);
			FailedVerify(sender, Proto::S_EBadParam, serial);
			return;
		}

		Proto::VerifyType way = req->type();
		if (way == Proto::VT_SIMPLE && _enable_simple) {
			VerifySimple(sender, req->token(), sid, req->code(), serial);
		} else if (way == Proto::VT_SINA) {
			VerifySina(sender, req->token(), sid, req->code(), serial);
		} else {
			LOG_ERR("[login]Verify failed. Bad provider : %d", (int)way);
			FailedVerify(sender, Proto::S_EBadParam, serial);
		}
	} else if (pf == Proto::REQ_CREATEROLE) {
		ReqCreate * req = Cast<ReqCreate>(msg);
		if (!req) return;

		int sid = (int)req->sid();
		if (_valid_servers.find(sid) == _valid_servers.end()) {
			LOG_ERR("[login]Create role failed. Invalid sid : %d", sid);
			Proto::Login::RspCreate rsp;
			rsp.set_status(Proto::S_EBadParam);
			sender->Reply(Proto::RSP_ACTIVEACCOUNT, rsp, serial);
			return;
		}

		Link(req->account(), sender);
		CenterConnector::Instance().Create(req->account(), req->session(), req->sid(), req->name(), serial);
	} else {
		LOG_ERR("[login]Received unsupported message. PF : %d", pf);
	}
}

void LoginService::SetVerifyParam(int version, const std::string & servers, bool enable_simple) {
	_ver = version;
	_enable_simple = enable_simple;

	auto valid = Split(servers, ",");
	for (auto & sid : valid) {
		_valid_servers[Convert<int>(sid)] = true;
	}
}

void LoginService::Link(const std::string & account, Sender * sender) {
	_processing[account] = sender->Id();
}

Sender * LoginService::Unlink(const std::string & account) {
	auto it = _processing.find(account);
	if (it == _processing.end()) return nullptr;
	Sender * client = Find(it->second);
	_processing.erase(it);
	return client;
}

void LoginService::FailedVerify(Sender * sender, int reason, uint32_t serial, bool threadsafe /* = false */) {
	if (!sender) return;

	RspVerify rsp;
	rsp.set_status((Proto::Status)reason);
	sender->Reply(Proto::RSP_VERIFY, rsp, serial, threadsafe);
}

void LoginService::FailedCreate(Sender * sender, int reason, uint32_t serial) {
	if (!sender) return;

	RspCreate rsp;
	rsp.set_status((Proto::Status)reason);
	sender->Reply(Proto::RSP_CREATEROLE, rsp, serial);
}